package influence.propagation.implementation;

import org.neo4j.graphdb.DynamicLabel;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Label;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.ResourceIterator;

import influence.propagation.core.Model;
import influence.propagation.core.ModelBuilder;
import influence.propagation.exception.IllegalArgumentException;
import influence.propagation.exception.InputFormatException;
import static influence.propagation.implementation.DefaultGraphParser.REGEX_1;
import static influence.propagation.implementation.DefaultGraphParser.REGEX_2;

public class IndependentCascadeModelBuilder implements ModelBuilder {
	
	private GraphDatabaseService db;
	private IndependentCascadeModel model = null;
	private int state = 0;
	private Node node1 = null;
	private Node node2 = null;
	private Label nodeLabel = DynamicLabel.label("NODE");
	private Label activeNodeLabel = DynamicLabel.label("ACTIVE");

	protected IndependentCascadeModelBuilder(GraphDatabaseService db) {
		this.db = db;
		this.model = new IndependentCascadeModel(db);
	}

	@Override
	public void create(String token) throws InputFormatException {
		switch (state) {
		case 0:
			control(token, REGEX_1);
			state = 1;
			createNode(1, token);
			break;
		case 1:
			control(token, REGEX_1);
			state = 2;
			createNode(2, token);
			break;
		case 2:
			control(token, REGEX_2);
			state = 0;
			createRelationship(token);
			break;
		default:
			throw new IllegalStateException();
		}
	}

	private void createRelationship(String token) {
		Relationship r = node1.createRelationshipTo(node2, RelType.WEIGHT_EDGE);
		r.setProperty(RelType.wheightPropertyKeyName(),
				Double.parseDouble(token));
	}

	private void createNode(int who, String token) {
		ResourceIterator<Node> it = db.findNodesByLabelAndProperty(nodeLabel,
				ActiveNodeProperties.NAME.toString(), token)
				.iterator();
		if(it.hasNext()){
			if(who==1){
				node1=it.next();
			}else{
				node2=it.next();
			}
			it.close();
			return;
		}
		if (who == 1) {
			node1 = db.createNode(nodeLabel);
			node1.setProperty(ActiveNodeProperties.NAME.toString(),
					token);
		} else {
			node2 = db.createNode(nodeLabel);
			node2.setProperty(ActiveNodeProperties.NAME.toString(),
					token);
		}
	}

	private void control(String token, String regex)
			throws InputFormatException {
		if (!token.matches(regex)) {
			throw new InputFormatException("token non accettato:" + token);
		}
	}

	@Override
	public Model getInstance() {
		return model;
	}

	@Override
	public void createActiveNode(String name) throws IllegalArgumentException {
		ResourceIterator<Node> it = db.findNodesByLabelAndProperty(nodeLabel,
				ActiveNodeProperties.NAME.toString(), name)
				.iterator();
		if (!it.hasNext()) {
			throw new IllegalArgumentException("Nodo " + name + "non trovato");
		}
		Node n = it.next();
		it.close();
		n.addLabel(activeNodeLabel);
		model.addActiveNode(model.createNewActiveNode(n));
	}
}
